package com.fingard.dsp.bank.directbank.abc23;


import java.util.ArrayList;

import com.fingard.constant.Format;
import com.fingard.dsp.bank.directbank.FailCode;
import com.fingard.dsp.bank.directbank.PaymentState;
import com.fingard.dsp.bank.directbank.SendBankRespose;
import com.fingard.dsp.bank.directbank.bankInterface.ISinglePay;
import com.fingard.dsp.bank.reqrespobj.single.*;
import com.fingard.dsp.bank.reqrespobj.single.detail.ReqPayRecDetail;
import com.fingard.dsp.bank.reqrespobj.single.detail.ReqQrySglBatPayDetail;
import com.fingard.dsp.bank.reqrespobj.single.detail.RetAtsSglDetail;
import com.fingard.generalobj.ExecResponse;
import com.fingard.net.ConnState;
import com.fingard.text.StringHelper;
import com.fingard.xml.XElement;
import com.fingard.xml.XmlTextReader;
import com.fingard.xml.XmlTextWriter;

/**农行智惠保*/
public class ABC23SinglePay extends ABC23Base implements ISinglePay {
	
	//单笔支付，不需采用流处理方式
	public RetAtsSingle d_1908_SglPay(ReqSingle p_req1908) throws Exception{
		//返回ATS的对象
		RetAtsSingle retAts = new RetAtsSingle(p_req1908.reqHeader);
		RetAtsSglDetail tmpRetDetail;

		tmpRetDetail = d_190802(p_req1908);
	
		if(tmpRetDetail.respCode.equals("-1") && StringHelper.isNullOrEmpty(tmpRetDetail.reqSeqID)){
			tmpRetDetail.reqSeqID = p_req1908.singleDetail.askNumber;
		}
		retAts.writeRetDetail(tmpRetDetail);
		return retAts;
	}

	@Override
	public RetAtsSingleBat d_1908BAT_SglBatPay(ReqSingleBat p_req1908BAT) throws Exception {
		RetAtsSingleBat retAts = new RetAtsSingleBat(p_req1908BAT);
		retAts.reqBatchNO = p_req1908BAT.reqBatchNO;
		retAts.batRespCode = "0";
        retAts.batTransState = "";
        retAts.batPayInfoCode = "";
		while (p_req1908BAT.readRecord()) {
			ReqPayRecDetail tmpDetail = p_req1908BAT.readedDetail;
			ReqSingle req1908 = new ReqSingle(p_req1908BAT.reqHeader);
			req1908.singleDetail = tmpDetail;
			RetAtsSingle eachRet = d_1908_SglPay(req1908);
			
			retAts.writeRetDetail(eachRet.retDetail);
		}
		retAts.writeAfterDetail();
        return retAts;
	}

	/**190802对外支付*/
	private RetAtsSglDetail d_190802(ReqSingle p_req1908) throws Exception{
		RetAtsSglDetail retDetail = new RetAtsSglDetail();
		
		try {
			//赋值通用参数
			ABC23Header bankHeader = new ABC23Header();
			bankHeader.cmdTypeCode = "10009";
			bankHeader.transSeqID = p_req1908.reqHeader.transSeqID;
			
			/**签名字段说明：
EnterpriseNum_TransNo_EnterpriseAccNum_CustAccNum_CustAccName_Amount
*/
			String tmpCustAccNum = p_req1908.singleDetail.recAct;
			String tmpAmount = Format.DecimalAmtFormat.format(p_req1908.singleDetail.getPayAmount());
			ArrayList<String> paramArray = new ArrayList<String>();
			paramArray.add(bankFront.org);
			paramArray.add(p_req1908.singleDetail.askNumber);
			paramArray.add(p_req1908.singleDetail.payAct);
			paramArray.add(tmpCustAccNum);
			paramArray.add(p_req1908.singleDetail.recName);
			paramArray.add(tmpAmount);
			String toSignStr = StringHelper.join("_", paramArray);
			WriteBankLogLn("签名字段EnterpriseNum_TransNo_EnterpriseAccNum_CustAccNum_CustAccName_Amount\r\n签名原文："+toSignStr);
			ExecResponse signResp = this.sign(toSignStr);
			if(signResp.isSucceed){
				bankHeader.verifyCode = signResp.getResultAsString();
			}else{
				retDetail.respCode = "0";
				retDetail.respInfo = "签名失败：" + signResp.logMsg;
				retDetail.reqSeqID = p_req1908.singleDetail.askNumber;
				retDetail.transState = PaymentState.FAIL_Payment;
				retDetail.payInfoCode = FailCode.E9981;
				return retDetail;
			}
			
			XmlTextWriter xmlWriter = new XmlTextWriter();//发银行报文的XML对象
			//写入通用的头部节点
			writeCommonHeader(xmlWriter, bankHeader);
			xmlWriter.writeStartElement("RealTimeSingleTransReq");
			/**1：同行代付
2：同行代收
3：人行大小额跨行付：
用于文件名和文件头信息。用来标及文件中的交易需要根据加急标记和金额大小两个信息来决定走大额还是小额。流程如下：
对交易明细中的 IsUrgent 加急标记进行判断。
如果为加急，则直接走大额。
如果不加急，根据交易金额判断走大额还是小额。
  交易金额<50000（非工作日500000），走小额
  交易金额>=50000（非工作日500000），走大额

4：银联跨行代收
5：人行大额跨行付：
用于文件名，和文件头信息。用来标记整个文件的处理方式，表示整个文件不管交易金额大小，不管具体交易的交易类型，都走大额。

6：人行网银互联跨行付
7：综合代付：
将交易类型为1、3、5、6、9的数据整合在一个批次，银行需根据不同交易类型重新组包发送不同渠道；
8：综合代收：
将交易类型为2、4的数据整合在一个批次，银行需根据不同交易类型重新组包发送不同渠道；
9：银联代付
*/
			if("1".equals(p_req1908.singleDetail.sameBnk)){
				xmlWriter.writeElementString("MoneyWay", "1");//用综合代付
			}else{
				xmlWriter.writeElementString("MoneyWay", "3");
			}
			xmlWriter.writeElementString("TransDate", Format.Date8Format.format(p_req1908.singleDetail.getPayDateTime()));
			
			String tmpDayFlowNo = getBankConfig().getMapValueByKey("dayFlowNoMapping", p_req1908.singleDetail.payAct);
			xmlWriter.writeElementString("DayFlowNo", tmpDayFlowNo);//原合并入账标记入账编号
			
			//WorkDayFlag工作日标记，用于大小额判断金额0：工作日     1：非工作日
			if("0".equals(p_req1908.singleDetail.workDayFlag)){
				xmlWriter.writeElementString("WorkDayFlag", "1");//1：非工作日
			}else{
				xmlWriter.writeElementString("WorkDayFlag", "0");//0：工作日
			}
			xmlWriter.writeElementString("AccountingFlag", "1");
			
			
			//需要进行对账码拼接以及节点解析，采用XElement进行处理
			XElement tmpXElement = new XElement("Trans","");
			tmpXElement.addChild(new XElement("TransNo", p_req1908.singleDetail.askNumber));
			tmpXElement.addChild(new XElement("EnterpriseAccNum", p_req1908.singleDetail.payAct));
			String tmpCustBankCode = convertBankToBank(p_req1908.singleDetail.recBankCode);
			if(StringHelper.isNullOrEmpty(tmpCustBankCode)){
				tmpCustBankCode = p_req1908.singleDetail.recBankCode;
			}
			tmpXElement.addChild(new XElement("CustBankCode", tmpCustBankCode));
			
			tmpXElement.addChild(new XElement("CustAccNum", tmpCustAccNum));
			tmpXElement.addChild(new XElement("CustAccName", p_req1908.singleDetail.recName));
			
			String tmpAreaCode = this.convertAreaToBank(p_req1908.singleDetail.recArea);
			if(StringHelper.isNullOrEmpty(tmpAreaCode)){
				tmpAreaCode = p_req1908.singleDetail.recArea;
			}
			if (getBankConfig().getValueAsBool("useActInfoSetCustArea")) {
                if ((p_req1908.singleDetail.recAct.indexOf('-') > 0 && p_req1908.singleDetail.recAct.length() == 18) || (p_req1908.singleDetail.recAct.length() == 17)) {
                	tmpAreaCode = p_req1908.singleDetail.recAct.substring(0, 2);
                }
            }
			tmpXElement.addChild(new XElement("AreaCode", tmpAreaCode));
			tmpXElement.addChild(new XElement("BankLocationCode", p_req1908.singleDetail.getCnapsCodeNot999()));
			tmpXElement.addChild(new XElement("BankLocationName", p_req1908.singleDetail.getOppBankLocation()));
			
			/*11)	ENCardType(1个字节)：卡折标记
			0：卡
			1：折
			默认值为0卡
			*/
			String tmpCardType = "";
			if("1".equals(p_req1908.singleDetail.isPrivate)){
				if("1".equals(p_req1908.singleDetail.cardType)){
					tmpCardType = "1";
				}else{
					tmpCardType = "0";
				}
			}
			tmpXElement.addChild(new XElement("CardType", tmpCardType));
			
			/**ENPrivate(1个字节)：公私标记    0：私人   1：公司   默认值为 0私人*/
			if("1".equals(p_req1908.singleDetail.isPrivate)){
				tmpXElement.addChild(new XElement("IsPrivate", "0"));
				
				
				
			}else{
				tmpXElement.addChild(new XElement("IsPrivate", "1"));
			}
			
			/**0：不加急     1：加急     默认值为0不加急*/
			if(p_req1908.singleDetail.paySpd.equals("1")){
				tmpXElement.addChild(new XElement("IsUrgent", "1"));
			}
			else{
				tmpXElement.addChild(new XElement("IsUrgent", "0"));
			}
			//以分为单位，签名和验签以元为单位
			String amtCent = StringHelper.amountMultiply100(p_req1908.singleDetail.payAmount);
			if(amtCent.length() == 1){
				amtCent = "00"+amtCent;
			}else if(amtCent.length() == 2){
				amtCent = "0"+amtCent;
			}
			tmpXElement.addChild(new XElement("Amount", amtCent));
			String cur = convertCurToBank(p_req1908.singleDetail.payCur);
			tmpXElement.addChild(new XElement("Currency", cur));
			String tmpCertType = this.convertCertTypeToBank(p_req1908.singleDetail.certType);
			if(StringHelper.hasAnyChar(tmpCertType) && StringHelper.hasAnyChar(p_req1908.singleDetail.certNum)){
				tmpXElement.addChild(new XElement("CertType", tmpCertType));
				tmpXElement.addChild(new XElement("CertNum", p_req1908.singleDetail.certNum));
			}else{
				tmpXElement.addChild(new XElement("CertType", ""));
				tmpXElement.addChild(new XElement("CertNum", ""));
			}
			tmpXElement.addChild(new XElement("Mobile", p_req1908.singleDetail.cellPhone));
			tmpXElement.addChild(new XElement("ReconciliationCode", p_req1908.singleDetail.abstractATS));
			
			
			String purpose = StringHelper.getFirstNotEmptyTrim(p_req1908.singleDetail.purpose,p_req1908.singleDetail.memo,p_req1908.singleDetail.description,p_req1908.singleDetail.useType);
			tmpXElement.addChild(new XElement("Abstract", StringHelper.subStringByByte(purpose, this.getCharset(), 8)));//客户方短摘要 8字节
			tmpXElement.addChild(new XElement("Purpose", StringHelper.subStringByByte(purpose, this.getCharset(), 64)));//64字节
			
			String memo = StringHelper.getFirstNotEmptyTrim(p_req1908.singleDetail.memo,p_req1908.singleDetail.description,p_req1908.singleDetail.useType);
			tmpXElement.addChild(new XElement("Memo", StringHelper.subStringByByte(memo, this.getCharset(), 64)));
			
			
			tmpXElement.addChild(new XElement("Extent1", ""));
			tmpXElement.addChild(new XElement("Extent2", ""));
			nodeAnalysis(p_req1908.singleDetail.srcXElement, tmpXElement, getCharset());
			xmlWriter.writeXElement(tmpXElement);
			
			xmlWriter.writeEndDocument();//写入报文完成
			StringBuilder chkSb = new StringBuilder();
			if(checkBankPayOverTime(p_req1908.singleDetail.getPayDateTime(), "5", chkSb)){
				SendBankRespose bkResp = sendToBank(xmlWriter.toXmlString());//发送银行
				
				//bkResp.connState = "";
				//bkResp.retMessage = FileHelper.readFileText("D:\\getToWork\\09-D银行接口文档\\ABC农行--融汇\\验签测试.txt", "gbk");
				
				if(bkResp.connState.length() == 0){
					StringBuilder tmpSbMsg = new StringBuilder();
					//解析银行返回
					String retCmdCode = bkResp.retMessage.substring(0, 5);
					String xmlPack = bkResp.retMessage.substring(5);
					XmlTextReader tmpBkReader = loadBankRespXmlReader(xmlPack, tmpSbMsg);
					if(tmpBkReader != null){
						processRetSingleDetail(retCmdCode, tmpBkReader, retDetail);
					}
					else{
						retDetail.respCode = "-1";
						retDetail.respInfo = tmpSbMsg.toString();
					}
				}
				else if(bkResp.connState.equals(ConnState.FAIL)){
					retDetail.respCode = "0";
					retDetail.respInfo = bkResp.retMessage;
					retDetail.reqSeqID = p_req1908.singleDetail.askNumber;
					retDetail.transState = PaymentState.FAIL_Payment;
					retDetail.payInfoCode = bkResp.connState;
				}
				else{
					retDetail.respCode = "-1";
					retDetail.respInfo = bkResp.retMessage;
					if(bkResp.sbLog!=null && bkResp.sbLog.length()>0){
						WriteBankLogLn(bkResp.sbLog.toString());
					}
				}
			}else{
				retDetail.respCode = "0";
				retDetail.respInfo = chkSb.toString();
				retDetail.reqSeqID = p_req1908.singleDetail.askNumber;
				retDetail.transState = PaymentState.FAIL_Payment;
				retDetail.payInfoCode = FailCode.E9999;
			}
			
		} catch (Exception ex) {
			retDetail.respCode = "-1";
			retDetail.respInfo = ex.getMessage();
			
			WriteBankLogLn(ex);
		}
		
		return retDetail;
	}
	
	/**单笔提交的响应和单笔查询的响应复用方法
	 * @throws Exception */
	private void processRetSingleDetail(String pCmdCode, XmlTextReader pReader, RetAtsSglDetail pDetail) throws Exception{
		String bkRespCode = pReader.getFirstText("/Root/Head/RespCode");
		if(!"0".equals(bkRespCode)){
			pDetail.respCode = "-1";
			pDetail.respInfo = pReader.getFirstText("/Root/Head/RespInfo");
			return;
		}
		String bkTransNodeName = "";
		if("10009".equals(pCmdCode)){
			bkTransNodeName = "RealTimeSingleTransResp";
		}else if("10010".equals(pCmdCode)){
			bkTransNodeName = "RealTimeSingleTransQueryResp";
		}
		//验签字段EnterpriseNum_CommandCode_MoneyWay_TransNo_CustBankCode_CustAccNum_CustAccName_Amount_State
		ArrayList<String> paramArray = new ArrayList<String>();
		paramArray.add(pReader.getFirstText("/Root/Head/EnterpriseNum"));
		paramArray.add(pCmdCode);
		paramArray.add(pReader.getFirstText("/Root/"+bkTransNodeName+"/MoneyWay"));
		paramArray.add(pReader.getFirstText("/Root/"+bkTransNodeName+"/Trans/TransNo"));
		paramArray.add(pReader.getFirstText("/Root/"+bkTransNodeName+"/Trans/CustBankCode"));
		paramArray.add(pReader.getFirstText("/Root/"+bkTransNodeName+"/Trans/CustAccNum"));
		paramArray.add(pReader.getFirstText("/Root/"+bkTransNodeName+"/Trans/CustAccName"));
		String oriAmt = pReader.getFirstText("/Root/"+bkTransNodeName+"/Trans/Amount");
		String tmpAmount = "";
		if(StringHelper.hasAnyChar(oriAmt)){
			tmpAmount = StringHelper.amountDivide100(oriAmt);
		}
		paramArray.add(tmpAmount);
		paramArray.add(pReader.getFirstText("/Root/"+bkTransNodeName+"/Trans/State"));
		
		String toVerifyStr = StringHelper.join("_", paramArray);
		WriteBankLogLn("验签字段EnterpriseNum_CommandCode_MoneyWay_TransNo_CustBankCode_CustAccNum_CustAccName_Amount_State\r\n验签原文："+toVerifyStr);
		String bkVerifyCode = pReader.getFirstText("/Root/Head/VerifyCode");
		ExecResponse signResp = this.verifySign(toVerifyStr, bkVerifyCode);
		if(!signResp.isSucceed){
			WriteBankLogLn("验签不通过："+signResp.logMsg);
			signResp.isSucceed = true;
		}
		if(signResp.isSucceed){
			pDetail.respCode = "0";
			pDetail.reqSeqID = pReader.getFirstText("/Root/"+bkTransNodeName+"/Trans/TransNo");
			pDetail.transAmt = tmpAmount;
			pDetail.transState = bkRespCode+"+"+pReader.getFirstText("/Root/"+bkTransNodeName+"/Trans/State");
			pDetail.payInfoCode = pReader.getFirstText("/Root/"+bkTransNodeName+"/Trans/InfoCode");
			pDetail.respInfo = pReader.getFirstText("/Root/"+bkTransNodeName+"/Trans/Info");
		}else{
			pDetail.respCode = "-1";
			pDetail.respInfo = "验签失败：" + signResp.logMsg;
			pDetail.respInfo = StringHelper.trimEnd(pDetail.respInfo, "：");
		}
	}

	//1944 状态查询
	public RetAtsSingle d_1944_QrySglPay(ReqQrySingle p_req1944) throws Exception{
		//返回ATS的对象
		RetAtsSingle retAts = new RetAtsSingle(p_req1944.reqHeader);
		
		RetAtsSglDetail tmpRetAtsDetail = new RetAtsSglDetail();
		tmpRetAtsDetail.respCode = "";

		if(tmpRetAtsDetail.respCode.length() == 0){
			ABC23Header bankHeader = new ABC23Header();
			bankHeader.cmdTypeCode = "10010";
			bankHeader.transSeqID = reqHeader.transSeqID;
			XmlTextWriter xmlWriter = new XmlTextWriter();//发银行报文的XML对象
			writeCommonHeader(xmlWriter, bankHeader);//写入通用的头部节点
			xmlWriter.writeStartElement("RealTimeSingleTransQueryReq");
			xmlWriter.writeElementString("TransNo", p_req1944.askNumber);
			xmlWriter.writeElementString("TransDate", Format.Date8Format.format(p_req1944.getBgnDateTime()));
			
			xmlWriter.writeEndDocument();
			try{
				SendBankRespose bkResp = sendToBank(xmlWriter.toXmlString());
				if(bkResp.connState.length() == 0){
					StringBuilder tmpSbMsg = new StringBuilder();
					String retCmdCode = bkResp.retMessage.substring(0, 5);
					String xmlPack = bkResp.retMessage.substring(5);
					XmlTextReader tmpBkReader = loadBankRespXmlReader(xmlPack, tmpSbMsg);
					if(tmpBkReader != null){
						processRetSingleDetail(retCmdCode, tmpBkReader, tmpRetAtsDetail);
					}
					else{
						tmpRetAtsDetail.respCode = "-1";
						tmpRetAtsDetail.respInfo = tmpSbMsg.toString();
					}
				}
				else{
					if(bkResp.sbLog!=null && bkResp.sbLog.length()>0){
						WriteBankLogLn(bkResp.sbLog.toString());
					}
					tmpRetAtsDetail.respCode = "-1";
					tmpRetAtsDetail.respInfo = bkResp.retMessage;
				}
			}
			catch (Exception ex) {
				tmpRetAtsDetail.respCode = "-1";
				tmpRetAtsDetail.respInfo = ex.getMessage();
				WriteBankLogLn(ex);
			}
		}
		retAts.writeRetDetail(tmpRetAtsDetail);
		return retAts;
	}

	@Override
	public RetAtsSingleBat d_1944BAT_QrySglBatPay(ReqQrySingleBat p_req1944BAT) throws Exception {
		RetAtsSingleBat retAts = new RetAtsSingleBat(p_req1944BAT.reqHeader);
        retAts.reqBatchNO = p_req1944BAT.reqBatchNO;
        try {
            //if(this.getBankConfig().getValueAsBool("getNewNoticeFor1944BAT")){
            //先调用获取新通知
            //	GetNewNotice();
            //}
            retAts.batRespCode = "0";
            while (p_req1944BAT.readRecord()) {
            	ReqQrySglBatPayDetail tmpDetail = p_req1944BAT.readedDetail;
            	ReqQrySingle req1944 = new ReqQrySingle(tmpDetail, p_req1944BAT.reqHeader);
            	RetAtsSingle resp1944 = d_1944_QrySglPay(req1944);
            	retAts.writeRetDetail(resp1944.retDetail);
            }
        }catch (Exception ex) {

            WriteBankLogLn(ex);
            retAts = new RetAtsSingleBat(p_req1944BAT.reqHeader);
            retAts.batRespCode = "-1";
            retAts.batRespInfo = ex.getMessage();
        }

        retAts.writeAfterDetail();
        return retAts;
	}
}
